﻿Imports System.Reflection

''' <summary>
''' Represents the learned schema of a field in a table, based on attributes that had been applied to properties
''' in entity-based classes when the schema was determined.
''' </summary>
Public Class FieldSchema

    Private _table As TableSchema = Nothing

    ''' <summary>
    ''' Gets the table that contains the field.
    ''' </summary>
    ''' <value>The table containing this field.</value>
    Public ReadOnly Property Table As TableSchema
        Get
            Return _table
        End Get
    End Property

    Private _fieldType As Type

    Public ReadOnly Property FieldType As Type
        Get
            Return _fieldType
        End Get
    End Property

    Private _attribute As FieldAttribute

    Private _name As String

    ''' <summary>
    ''' Gets the name of the field.
    ''' </summary>
    ''' <value>The name of the field.</value>
    Public ReadOnly Property Name As String
        Get
            Return _name
        End Get
    End Property
    
    ''' <summary>
    ''' Gets the display name of the field.
    ''' </summary>
    ''' <value>The display name of the field.</value>
    Public ReadOnly Property DisplayName As String
        Get
            If _attribute.DisplayName <> "" Then Return _attribute.DisplayName
            Return _name
        End Get
    End Property

    Private _assignedPickList As PickListAttribute

    Public ReadOnly Property AssignedPickList As PickListAttribute
        Get
            Return _assignedPickList
        End Get
    End Property

    Private _assignedLookup As LookupAttribute

    Public ReadOnly Property AssignedLookup As LookupAttribute
        Get
            Return _assignedLookup
        End Get
    End Property

    Private _dateDetails As DateDetailsAttribute

    Public ReadOnly Property DateDetails As DateDetailsAttribute
        Get
            Return _dateDetails
        End Get
    End Property

    Public ReadOnly Property IsDisplayColumn As Boolean
        Get
            Return _attribute.IsDisplayColumn
        End Get
    End Property

    Private _isPrimaryKey As Boolean

    Public ReadOnly Property IsPrimaryKey As Boolean
        Get
            Return _isPrimaryKey
        End Get
    End Property

    Private _isPasswordField As Boolean = False

    Public ReadOnly Property IsPasswordField As Boolean
        Get
            Return _isPasswordField
        End Get
    End Property

    Private _isMemoField As Boolean = False

    Public ReadOnly Property IsMemoField As Boolean
        Get
            Return _isMemoField
        End Get
    End Property

    Private Sub New(ByVal parent As TableSchema, ByVal attribute As FieldAttribute, ByVal name As String, ByVal fieldType As Type)
        Me._table = parent
        Me._attribute = attribute
        Me._name = name
        Me._fieldType = fieldType
    End Sub

    Public Function GetValue(ByVal entity As BaseEntity) As Object
        Return entity.GetType.GetProperty(Name).GetValue(entity, Nothing)
    End Function

    Public Sub SetValue(ByVal entity As BaseEntity, ByVal value As Object)

        Dim PropertyInfo As PropertyInfo = entity.GetType.GetProperty(Name)
        Dim ActualValue As Object = ConvertValue(value, PropertyInfo.PropertyType)
        PropertyInfo.SetValue(entity, ActualValue, Nothing)

    End Sub

    Friend Shared Function Create(ByVal parent As TableSchema, ByVal propertyInfo As PropertyInfo) As FieldSchema

        ' Create the field
        Dim FieldData As FieldAttribute = GetAttribute(Of FieldAttribute)(propertyInfo)
        Dim Result As New FieldSchema(parent, FieldData, propertyInfo.Name, propertyInfo.PropertyType)
        Result._isPrimaryKey = GetAttribute(Of PrimaryKeyAttribute)(propertyInfo) IsNot Nothing

        ' Is there a pick list assigned to the field?
        Dim PickList As PickListAttribute = GetAttribute(Of PickListAttribute)(propertyInfo)
        If PickList IsNot Nothing Then Result._assignedPickList = PickList

        ' Is there a lookup assigned to the field?
        Dim Lookup As LookupAttribute = GetAttribute(Of LookupAttribute)(propertyInfo)
        If Lookup IsNot Nothing Then Result._assignedLookup = Lookup

        ' Is a password attribute applied to the field?
        Dim Password As PasswordAttribute = GetAttribute(Of PasswordAttribute)(propertyInfo)
        If Password IsNot Nothing Then Result._isPasswordField = True

        ' Is a password attribute applied to the field?
        Dim Memo As MemoAttribute = GetAttribute(Of MemoAttribute)(propertyInfo)
        If Memo IsNot Nothing Then Result._isMemoField = True

        ' Are date details applied to the field?
        Dim DateDetails As DateDetailsAttribute = GetAttribute(Of DateDetailsAttribute)(propertyInfo)
        If DateDetails IsNot Nothing Then Result._dateDetails = DateDetails

        ' Ensure there is no combination of pick list and lookup
        If PickList IsNot Nothing AndAlso Lookup IsNot Nothing Then Throw New Exception("The field cannot be assigned both a pick list and lookup.")

        ' Return the field
        Return Result

    End Function

End Class
